<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebShell</title>
    <link rel="stylesheet" href="static/element-ui/2.15.2/index.css">
    <style>
        html, body {
            margin: 0px;
            height:100%;
        }
        .contextmenu__item {
            display: block;
            line-height: 34px;
            text-align: center;
        }
        .contextmenu__item:not(:last-child) {
            border-bottom: 1px solid rgba(0, 0, 0, 0.1);
        }
        .menu {
            position: absolute;
            background-color: #fff;
            width: 100px;
            /*height: 106px;*/
            font-size: 12px;
            color: #444040;
            border-radius: 4px;
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
            border-radius: 3px;
            border: 1px solid rgba(0, 0, 0, 0.15);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
            white-space: nowrap;
            z-index: 1000;
        }
        .contextmenu__item:hover {
            cursor: pointer;
            background: #66b1ff;
            border-color: #66b1ff;
            color: #fff;
        }
        .el-menu {
            border-right: solid 0px #e6e6e6;
            list-style: none;
            position: relative;
            margin: 0;
            padding-left: 0;
            background-color: #FFF;
        }
        .el-menu-item, .el-submenu__title {
            height: 48px;
            line-height: 48px;
            position: relative;
            -webkit-box-sizing: border-box;
            white-space: nowrap;
            list-style: none;
        }
        .el-submenu__title {
            font-size: 14px;
            color: #303133;
            padding-left: 0px;;
            cursor: pointer;
            -webkit-transition: border-color .3s,background-color .3s,color .3s;
            transition: border-color .3s,background-color .3s,color .3s;
            box-sizing: border-box;
        }
        .el-menu-item-group__title {
            padding: 0px 0px 0px 0px;
            line-height: normal;
            font-size: 12px;
            color: #909399;
        }
        .el-submenu .el-menu-item {
            font-size: 12px;
            height: 32px;
            line-height: 32px;
            padding: 0px 0px;
            min-width: 32px;
        }
        .el-tree {
            position: relative;
            cursor: default;
            background: #545c64;
            color: #ffffff;
        }
        .el-tree-node__content:hover {
            background: none;
        }
         .el-tree-node:focus > .el-tree-node__content {
            background: none;
        }
        .el-tree-node.is-current > .el-tree-node__content {
            background-color: #606266;
        }
        .custom-tree-node {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: space-between;
            font-size: 14px;
            padding-right: 8px;
          }
        .el-tabs__header {
            padding: 0;
            position: relative;
            margin: 0 0 0px;
        }
        .el-tabs__item {
            padding: 0 10px;
            height: 32px;
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
            line-height: 32px;
            display: inline-block;
            list-style: none;
            font-size: 14px;
            font-weight: 500;
            color: #303133;
            position: relative;
        }
        .el-tabs__content {
            overflow: hidden;
            position: relative;
            height: calc(100% - 32px);
        }
        .el-tabs--card>.el-tabs__header .el-tabs__nav {
            border: 0px solid #E4E7ED;
            border-bottom: none;
            border-radius: 4px 4px 0 0;
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
        }
        .el-tabs--card>.el-tabs__header {
            border-bottom: 0px solid #E4E7ED;
        }
        .el-tabs__nav-wrap {
            overflow: hidden;
            margin-bottom: 0px;
            position: relative;
        }
    </style>
</head>
<body>
<div id="hosts" style="height: 100%">
    <el-row style="height: 100%">
        <el-col :span="4" style="height: 100%;background-color: #545c64; ">
            <div @contextmenu.prevent="showContextMenu($event)" style="height: 100%;">
                <div class="custom-tree-container">
                    <div class="block">
                        <el-tree :data="host_list" node-key="id" :props="treeProps" default-expand-all :expand-on-click-node="false" @node-contextmenu="rightClick">
                            <span class="custom-tree-node" slot-scope="{ node, data }">
                                <span>[[ data.name | ellipsis ]]</span>
                                <span>
                                    <el-button v-if="!('hosts' in data)" type="text" style="color:#ffffff" size="mini" @click="() => connectSSH(data)"> SSH </el-button>
                                    <el-button v-if="!('hosts' in data)" type="text" style="color:#ffffff" size="mini" @click="() => connectSFTP(data)"> SFTP </el-button>
                                </span>
                            </span>
                        </el-tree>
                    </div>
                </div>
            </div>
        </el-col>
        <el-col :span="20" style="height: 100%">
            <el-tabs v-model="tabs_info.active_tab" type="card" closable @tab-remove="removeTab" style="height: 100%">
                <el-tab-pane :key="item.index" :name="item.index" :label="item.title" v-for="(item, index) in tabs_info.tab_list" style="height: 100%;">
                    <iframe :src="item.webshell_url" frameborder="0" scrolling="no" width="100%" height="100%"></iframe>
                </el-tab-pane>
            </el-tabs>

        </el-col>
    </el-row>

    <el-dialog title="主机" width="30%" :visible.sync="host_dialog_info.visible" :close-on-click-modal="false" @close="closeHostDialog">
        <div slot="title"><span class="el-dialog__title">[[ host_dialog_title ]]</span></div>
        <el-row>
            <el-col :md="24" :xs="24">
                <el-form :inline="true" :model="host_form" :rules="host_rules" ref="host_form" label-width="130px">
                    <el-form-item label="主机名称：" prop="name" style="width:100%">
                        <el-input v-model="host_form.name" placeholder="请输入主机名称"></el-input>
                    </el-form-item>
                    <el-form-item label="IP地址：" prop="ip" style="width:100%">
                        <el-input v-model="host_form.ip" placeholder="请输入IP地址"></el-input>
                    </el-form-item>
                    <el-form-item label="端口号：" prop="port" style="width:100%">
                        <el-input v-model="host_form.port" placeholder="请输入端口号"></el-input>
                    </el-form-item>
                    <el-form-item label="用户名：" prop="username" style="width:100%">
                        <el-input v-model="host_form.username" placeholder="请输入用户名"></el-input>
                    </el-form-item>
                    <el-form-item label="密码：" prop="password" style="width:100%">
                        <el-input type="password" v-model="host_form.password" placeholder="请输入密码"></el-input>
                    </el-form-item>
                    <!--
                        <el-form-item label="认证方式：" prop="auth_type" style="width:100%">
                            <el-input v-model="host_form.auth_type" placeholder="认证方式"></el-input>
                        </el-form-item>
                    -->
                    <el-form-item label="所属主机组">
                        <el-select v-model="host_form.host_group_id" placeholder="选择主机组">
                            <el-option v-for="item in host_list" :label="item.name" :value="item.id" :key="item.id"></el-option>
                        </el-select>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
        <div slot="footer" class="dialog-footer">
            <el-button type="primary" @click="closeHostDialog">取 消</el-button>
            <el-button type="primary" @click="saveHost">确 定</el-button>
        </div>
    </el-dialog>

    <el-dialog title="主机组" width="30%" :visible.sync="host_group_dialog_info.visible" :close-on-click-modal="false" @close="closeHostGroupDialog">
        <div slot="title"><span class="el-dialog__title">[[ host_group_dialog_title ]]</span></div>
        <el-row>
            <el-col :md="24" :xs="24">
                <el-form :inline="true" :model="host_group_form" :rules="host_group_rules" ref="host_group_form" label-width="130px">
                    <el-form-item label="主机组名称：" prop="name" style="width:100%">
                        <el-input v-model="host_group_form.name" placeholder="请输入主机组名称"></el-input>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
        <div slot="footer" class="dialog-footer">
            <el-button type="primary" @click="closeHostGroupDialog">取 消</el-button>
            <el-button type="primary" @click="saveHostGroup">确 定</el-button>
        </div>
    </el-dialog>

    <el-dialog :visible.sync="warning_message_dialog_info.visible" width="30%" :show-close="false">
         <div slot="title" class="dialog-title">
             <i class="el-icon-info" style="color:#E6A23C;"></i>
             <span class="title-text">警告</span>
         </div>

        <span>[[ warning_message_dialog_info.message ]]</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="handleWarningMessageNo">取 消</el-button>
            <el-button type="primary" @click="handleWarningMessageYes">确 定</el-button>
        </span>
    </el-dialog>

    <div id="contextmenu" v-show="contextmenu_info.visible" class="menu">
        <div v-if="contextmenu_info.menu_state === 1" class="contextmenu__item" @click="addHost">添加主机</div>
        <div v-if="contextmenu_info.menu_state === 0" class="contextmenu__item" @click="addHostGroup">添加主机组</div>
        <div v-if="contextmenu_info.menu_state === 2" class="contextmenu__item" @click="editHost">编辑主机</div>
        <div v-if="contextmenu_info.menu_state === 1" class="contextmenu__item" @click="editHostGroup">编辑主机组</div>
        <div v-if="contextmenu_info.menu_state === 2" class="contextmenu__item" @click="deleteNode">删除主机</div>
        <div v-if="contextmenu_info.menu_state === 1" class="contextmenu__item" @click="deleteNode">删除主机组</div>
    </div>
</div>

<script src="static/js/axios.min.js"></script>
<script src="static/js/ajax.js"></script>
<script src="static/vue/v2.6.12/vue.js"></script>
<script src="static/element-ui/2.15.2/index.js"></script>
<script>
    let app = new Vue({
        delimiters: ["[[", "]]"],
        el: '#hosts',
        data: {
            host_url: 'http://' + document.domain + ':' + location.port + '/host',
            host_group_url: 'http://' + document.domain + ':' + location.port + '/hostgroup',
            host_list : [],
            host_dialog_title: "",
            host_form: {
                id: "",
                name: "",
                ip: "",
                port: "",
                username: "",
                password: "",
                auth_type: "password",
                host_group_id: ""
            },
            host_dialog_info: {
                visible: false,
                edit_active: false,
            },
            host_rules: {
                name: [
                    { required: true, message: '请输入主机组名称', trigger: 'blur' },
                ],
                ip: [
                    { required: true, message: '请输入IP地址', trigger: 'blur' },
                ],
                port: [
                    { required: true, message: '请输入端口号', trigger: 'blur' },
                ],
                username: [
                    { required: true, message: '请输入用户名', trigger: 'blur' },
                ],
                password: [
                    { required: true, message: '请输入密码', trigger: 'blur' },
                ],
                auth_type: [
                    { required: true, message: '请选择认证方式', trigger: 'blur' },
                ],
                host_group_id: [
                    { required: true, message: '请选择主机组', trigger: 'blur' },
                ]
            },
            host_group_dialog_title: "",
            host_group_form: {
                id: "",
                name: ""
            },
            host_group_dialog_info: {
                visible: false,
                edit_active: false,
            },
            host_group_rules: {
                name: [
                    { required: true, message: '请输入主机组名称', trigger: 'blur' },
                ]
            },
            treeProps: {
                value: "id",
                label: "name",
                children: "hosts"
            },
            tabs_info: {
                active_tab: '',
                tab_list: [],
                tab_index: ''
            },
            warning_message_dialog_info: {
                visible: false,
                message: "",
                handle_fun: null,
            },
            contextmenu_info: {
                visible:false,
                menu_state: 0,
                edit_data: ""
            }
        },
        methods: {
            getHostList() {
                let _self = this;
                ajax.get(_self.host_url).then(function (response) {
                    if (response.data.code == 0) {
                        _self.host_list = response.data.data
                    }
                    else {
                        _self.$message.warning('获取主机列表失败，请刷新页面重试！')
                    }
                });
            },
            addHost() {
               let _self = this;
                _self.host_dialog_title = "添加主机组"
                _self.host_dialog_info.visible = true;
                _self.host_dialog_info.edit_active = false;
                _self.getHostList();
            },
            addHostGroup() {
                let _self = this;
                _self.host_group_dialog_title = "添加主机"
                _self.host_group_dialog_info.visible = true;
                _self.host_group_dialog_info.edit_active = false;
                _self.getHostList();
            },
            editHost() {
                let _self = this;
                let host_id = _self.contextmenu_info.edit_data.id
                ajax.get(_self.host_url + "?host_id=" + host_id).then(function (response) {
                    if (response.data.code == 0) {
                        _self.host_form = response.data.data;
                        _self.host_form.password = window.atob(response.data.data.password);
                        _self.host_dialog_title = "编辑主机"
                        _self.host_dialog_info.visible = true;
                        _self.host_dialog_info.edit_active = true;
                    }
                    else {
                        _self.$message.warning('获取数据失败，请刷新页面重新获取！')
                    }
                }).catch(function (error) {
                    _self.$message.error(error.message);
                });
            },
            editHostGroup() {
                let _self = this;
                _self.host_group_form.id = _self.contextmenu_info.edit_data.id;
                _self.host_group_form.name = _self.contextmenu_info.edit_data.name;
                _self.host_group_dialog_title = "编辑主机组"
                _self.host_group_dialog_info.visible = true;
                _self.host_group_dialog_info.edit_active = true;
            },
            deleteHost() {
                let _self = this;
                let params = {
                        id_list: [_self.contextmenu_info.edit_data.id],
                    };
                ajax.delete(_self.host_url, {data: params}).then(function (response) {
                    if (response.data.code === 0) {
                        _self.$message.success('删除成功！');
                    } else {
                        _self.$message.error(response.data.msg);
                    }
                }).catch(function (error) {
                    _self.$message.error(error.message);
                });
                 _self.getHostList();
            },
            deleteHostGroup() {
                let _self = this;
                let params = {
                        id_list: [_self.contextmenu_info.edit_data.id],
                    };
                ajax.delete(_self.host_group_url, {data: params}).then(function (response) {
                    if (response.data.code === 0) {
                        _self.$message.success('删除成功！');
                    } else {
                        _self.$message.error(response.data.msg);
                    }
                }).catch(function (error) {
                    _self.$message.error(error.message);
                });
                 _self.getHostList();
            },
            deleteNode() {
                let _self = this;
                if ("hosts" in _self.contextmenu_info.edit_data) {
                    _self.warning_message_dialog_info.message = "确定删除这个主机组吗？"
                    _self.warning_message_dialog_info.handle_fun = _self.deleteHostGroup
                } else {
                    _self.warning_message_dialog_info.message = "确定删除这个主机吗？"
                    _self.warning_message_dialog_info.handle_fun = _self.deleteHost
                }
                _self.warning_message_dialog_info.visible = true;
            },
            connectSSH(data) {
                let _self = this
                let tab_index = ++_self.tabs_info.tab_index + '';
                _self.tabs_info.tab_list.push({
                    index: tab_index,
                    title:  data.name,
                    host_id: data.id,
                    webshell_url: 'http://' + document.domain + ':' + location.port + '/webshell?host_id=' + data.id
                });
                _self.tabs_info.active_tab = tab_index;
            },
            connectSFTP(data) {

            },
            removeTab(targetTab) {
                let _self = this
                let tabs = _self.tabs_info.tab_list;
                let active_tab = _self.tabs_info.active_tab;
                if (active_tab === targetTab) {
                    tabs.forEach((tab, index) => {
                        if (tab.index === targetTab) {
                            let next_tab = tabs[index + 1] || tabs[index - 1];
                            if (next_tab) {
                                active_tab = next_tab.index;
                            }
                        }
                    });
                }
                _self.tabs_info.active_tab = active_tab;
                _self.tabs_info.tab_list = _self.tabs_info.tab_list.filter(tab => tab.index !== targetTab);
            },
            saveHost() {
                let _self = this;
                if (_self.host_dialog_info.edit_active) {
                    let params = {
                        id: _self.host_form.id,
                        name: _self.host_form.name,
                        ip: _self.host_form.ip,
                        port: _self.host_form.port,
                        username: _self.host_form.username,
                        password: window.btoa(_self.host_form.password),
                        auth_type: _self.host_form.auth_type,
                        host_group_id: _self.host_form.host_group_id,
                    };
                    ajax.put(_self.host_url, params).then(function (response) {
                        if (response.data.code === 0) {
                            _self.$message.success('修改成功！');
                        } else {
                            _self.$message.error(response.data.msg);
                        }
                    }).catch(function (error) {
                        _self.$message.error(error.message);
                    });
                } else {
                    let params = {
                        name: _self.host_form.name,
                        ip: _self.host_form.ip,
                        port: _self.host_form.port,
                        username: _self.host_form.username,
                        password: window.btoa(_self.host_form.password),
                        auth_type: _self.host_form.auth_type,
                        host_group_id: _self.host_form.host_group_id,
                    };
                    ajax.post(_self.host_url, params).then(function (response) {
                        if (response.data.code === 0) {
                            _self.$message.success('添加成功！');
                        } else {
                            _self.$message.error(response.data.msg);
                        }
                    }).catch(function (error) {
                        _self.$message.error(error.message);
                    });
                };
                _self.getHostList();
                _self.closeHostDialog();
            },
            saveHostGroup() {
                let _self = this;
                if (_self.host_group_dialog_info.edit_active) {
                    let params = {
                        id: _self.host_group_form.id,
                        name: _self.host_group_form.name
                    };
                    ajax.put(_self.host_group_url, params).then(function (response) {
                        if (response.data.code === 0) {
                            _self.$message.success('修改成功！');
                        } else {
                            _self.$message.error(response.data.msg);
                        }
                    }).catch(function (error) {
                        _self.$message.error(error.message);
                    });
                } else {
                    let params = {
                        name: _self.host_group_form.name
                    };
                    ajax.post(_self.host_group_url, params).then(function (response) {
                        if (response.data.code === 0) {
                            _self.$message.success('添加成功！');
                        } else {
                            _self.$message.error(response.data.msg);
                        }
                    }).catch(function (error) {
                        _self.$message.error(error.message);
                    });
                };
                _self.getHostList();
                _self.closeHostGroupDialog();
            },
            closeHostDialog() {
                let _self = this;
                _self.host_dialog_info.visible = false;
                _self.host_dialog_info.edit_active = false;
                _self.$refs["host_form"].resetFields();
            },
            closeHostGroupDialog() {
                let _self = this;
                _self.host_group_dialog_info.visible = false;
                _self.host_group_dialog_info.edit_active = false;
                _self.$refs["host_group_form"].resetFields();
            },
            handleWarningMessageYes() {
                let _self = this;
                _self.warning_message_dialog_info.handle_fun(_self.contextmenu_info.edit_data.id);
                _self.warning_message_dialog_info.visible = false;
            },
            handleWarningMessageNo() {
                let _self = this;
                _self.warning_message_dialog_info.visible = false;
            },
            showContextMenu(e) {
                let _self = this;
                _self.contextmenu_info.visible = false;
                _self.contextmenu_info.visible = true;
                _self.contextmenu_info.menu_state = 0
                let menu = document.querySelector('#contextmenu')
                _self.styleMenu(menu)
            },
            rightClick(event, data, node, component) {
                let _self = this;
                _self.contextmenu_info.visible = false;
                _self.contextmenu_info.visible = true;
                _self.contextmenu_info.edit_data = data
                event.preventDefault();
                if ("hosts" in data) {
                    _self.contextmenu_info.menu_state = 1
                } else {
                    _self.contextmenu_info.menu_state = 2
                }
                let menu = document.querySelector('#contextmenu')
                _self.styleMenu(menu)
            },
            closeMenu() {
                let _self = this;
                _self.contextmenu_info.visible = false
                document.removeEventListener('click', _self.closeMenu) // 关掉监听，
            },
            styleMenu(menu) {
                let _self = this;
                if (event.clientX > 1800) {
                    menu.style.left = event.clientX - 100 + 'px'
                } else {
                    menu.style.left = event.clientX + 1 + 'px'
                }
                document.addEventListener('click', _self.closeMenu) // 给整个document新增监听鼠标事件，点击任何位置执行foo方法
                if (event.clientY > 700) {
                    menu.style.top = event.clientY - 30 + 'px'
                } else {
                    menu.style.top = event.clientY - 10 + 'px'
                }
            },
            disableKeyDown() {
                document.onkeydown = function (e) {
                    let evt = window.event || e;
                    let code = evt.keyCode || evt.which;
                    if (code == 116) {
                        if (evt.preventDefault) {
                            evt.preventDefault();
                        } else {
                            evt.keyCode = 0;
                            evt.returnValue = false
                        }
                    }
                    /*else if (code == 123) {
                        evt.cancelBubble = true;
                        evt.returnValue = false;
                    }*/
                }
            },
            disableContextMenu() {
                document.oncontextmenu = function (e) {
                    return false;
                };
            }
        },
        filters: {
            ellipsis(value) {
                if (!value) return "";
                if (value.length > 12) {
                    return value.slice(0, 12) + "...";
                }
                return value;
            }
          },
        mounted: function () {
            let _self = this;
            _self.getHostList();
            _self.disableKeyDown();
            _self.disableContextMenu();
        }
    })

</script>
</body>
</html>